"""
图片生成
"""

import math
import random

from PIL import (
    Image,
    ImageDraw,
    ImageFont,
)

from my_typing import *


def get_captcha_image(
    length: int = 6,
    height: int = 50,
    font: StrOrNone = None,
) -> tuple[str, bytes]:
    """
    获取随机生成的验证码图片

    Args:
        length: 验证码的长度
        height: 验证码图片的高度（宽度 = 验证码长度 * 验证码图片的高度）
        font: 字体（绝对路径）

    Returns:
        (验证码, 图片 bytes)
    """

    from utils.generator_utils import StringGenerator

    def _get_random_rgb() -> tuple[int, int, int]:
        """ 获取随机的 RGB 数值 """

        return (
            random.randint(0, 255),
            random.randint(0, 255),
            random.randint(0, 255),
        )

    width: int = height * length
    """ 图片宽度（高度 * 验证码长度） """

    font_size: int = math.ceil(height * 0.8)
    """ 字号大小（同 高度） """

    captcha_img: Image = Image.new(
        mode="RGB",
        size=(width, height),
        color=_get_random_rgb()
    )
    """ 验证码图片对象 """

    img_draw: ImageDraw = ImageDraw.Draw(captcha_img)
    """ 用于创建图像标注、生成验证码、图像识别 """

    img_font: ImageFont.FreeTypeFont = ImageFont.truetype(font, font_size)
    """ 字体 """

    captcha: str = StringGenerator.generate_random_str(length)
    """ 验证码 """

    word_spacing: float = round((width - len(captcha) * font_size) / (len(captcha) + 1), 2)
    """ 字间距（字与字之间 and 字与边框之间 的间距） """

    margin_top: float = round((height - font_size) / 2 * 0.4, 2)
    """ 字体顶部和上边框的间距（需要考虑到字体不会占满整个框，并且大部分位置都是偏下的，可能上面的 1/5 是空的） """

    for idx, word in enumerate(captcha):
        y: float = margin_top
        """
        Y 轴位置

        因为验证码是横向排列的，所以纵向位置是固定的
        """

        x: float = (word_spacing + font_size) * idx + word_spacing
        """
        X 轴位置（需要根据计算得出）

        需要根据每个字符的索引位置计算出横向位置：(字间距 + 字号大小) * 字符的索引下标 + 字间距
        """

        img_draw.text(
            xy=(x, y),
            text=word,
            fill=_get_random_rgb(),
            font=img_font
        )

    file: BytesIO = BytesIO()
    captcha_img.save(file, "png")

    return captcha, file.getvalue()
